package yl.hs.bmipfull.service.vehiclemanage.impl;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import yl.hs.bmipfull.daos.laboratory.IProductOverageDao;
import yl.hs.bmipfull.daos.production.IProductShipOrderDao;
import yl.hs.bmipfull.daos.production.IProductionLineDao;
import yl.hs.bmipfull.daos.production.IProductionTaskDao;
import yl.hs.bmipfull.daos.production.ITransTaskDao;
import yl.hs.bmipfull.daos.vehiclemanage.ITruckInfoDao;
import yl.hs.bmipfull.pojo.laboratory.ProductOverageEntity;
import yl.hs.bmipfull.pojo.production.ProductShipOrderEntity;
import yl.hs.bmipfull.pojo.production.ProductionTaskEntity;
import yl.hs.bmipfull.pojo.production.TransTaskEntity;
import yl.hs.bmipfull.pojo.vehiclemanage.TruckInfoEntity;
import yl.hs.bmipfull.service.vehiclemanage.ITruckInfoService;
import yl.hs.bmipfull.utils.*;
import yl.hs.bmipfull.utils.datastate.ActionType;
import yl.hs.bmipfull.utils.datastate.TruckState;
import yl.hs.bmipfull.utils.datastate.TruckType;
import yl.hs.bmipfull.viewmodels.PageQuery;
import yl.hs.bmipfull.viewmodels.PageResult;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 作用:  车辆信息服务层接口实现<br/>
 * 创建时间: 2021年05月20日 16时10分49秒 <br/>
 *
 * @author 谢东
 */
@Service
public class TruckInfoServiceImpl extends VehicleBaseService implements ITruckInfoService {

    @Autowired
    ITruckInfoDao dao;
    @Autowired
    ITransTaskDao Taskdao;
    @Autowired
    IProductOverageDao Overagedao;
    @Autowired
    IProductionTaskDao ProductTaskdao;
    @Autowired
    IProductShipOrderDao shipOrderdao;
    @Autowired
    IProductionLineDao linedao;

    @Override
    public List<TruckInfoEntity> queryMortarTruck() {
        return dao.queryMortarTruck();
    }

    @Override
    public Integer updateStateBySN(String sn, short state) {
        return dao.updateStateBySN(sn, state);
    }

    @Override
    public List<TruckInfoEntity> queryList(PageQuery pageQuery) throws Exception {
        pageQuery.checkSortSides(TruckInfoEntity.class);
        return dao.queryList(pageQuery.getQuery(), null);
    }

    @Override
    public List<TruckInfoEntity> queryLikeTaskSN(String taskSN) {
        return dao.queryLikeTaskSN(taskSN);
    }

    @Override
    public PageResult<TruckInfoEntity> queryPage(PageQuery pageQuery, int rowNum, int page) throws Exception {
        pageQuery.checkSortSides(TruckInfoEntity.class);
        pageQuery.getQuery().put("querySkip", (page - 1) * rowNum);
        pageQuery.getQuery().put("pageSize", rowNum);
        PageResult<TruckInfoEntity> result = new PageResult(rowNum);
        var filters = SearchFilterEngine.generateQueryList(pageQuery.getFilters(), TruckInfoEntity.class);
        result.setRecords(dao.queryCountByCondition(pageQuery.getQuery(), filters));
        result.setPage(page);
        result.setData(dao.queryPage(pageQuery.getQuery(), filters));
        return result;
    }


    @Override
    public TruckInfoEntity findBySn(String sn) {
        return dao.findBySN(sn);
    }

    @Override
    public Integer saveTruckInfo(Map<String, Object> model, String sn) throws Exception {
        Integer result = 0;
        TruckInfoEntity entity = new TruckInfoEntity();
        if (Tl.isEmpty(sn)) {
            //执行保存
            Tl.getChangeLog(entity, model);
            entity.setPYFieldValue();
            entity.setSn(queryNewSN(TruckInfoEntity.class));

            result = dao.insertNew(entity);
            if (result > 0) {
                writeLog(ActionType.CREATE, entity.getSn(), "插入车辆信息信息", Tl.toJson(entity), TruckInfoEntity.class);
            }

        } else {
            //执行修改
            entity = findBySn(sn);
            var changelog = Tl.getChangeLog(entity, model);
            entity.setPYFieldValue();
            result = dao.update(entity);
            if (result > 0) {
                writeLog(ActionType.UPDATE, sn, changelog, Tl.toJson(entity), TruckInfoEntity.class);
            }
        }
        if (result > 0) {
            saveGS(
                    entity.getSn(),
                    entity.getTruckPlate(),
                    String.join(",",
                            entity.getTruckPlate(),
                            entity.getDriverName(),
                            entity.getCardSNO(),
                            entity.getEquipmentCode(),
                            entity.getIpAdress(),
                            entity.getUserName(),
                            entity.getUseType(),
                            entity.getCardSNO()
                    ),
                    entity,
                    HsApp.getCurrent() != null ? HsApp.getCurrent().getUserSN() : null,
                    null
            );
        }
        return result;
    }

    @Override
    public Integer delete(String[] sn) {
        var result = dao.changeStateBySn(sn, DataState.DELETED.code);
        if (result > 0) {
            writeLog(ActionType.DELETE, sn, TruckInfoEntity.class);
            deleteGs(sn);
        }
        return result;
    }

    @Override
    public Integer recovery(String[] sn, short state) {
        var result = dao.changeStateBySn(sn, state);
        if (result > 0) {
            writeLog(ActionType.UPDATE, sn, TruckInfoEntity.class);
        }
        return result;
    }

    @Override
    public Integer changeStateBySn(String[] snArray, short state) {
        return dao.changeStateBySn(snArray, state);
    }

    @Override
    public Integer truckInfoVerification(String key, String value, String sn) {
        return dao.truckInfoVerification(key, value, sn);
    }

    @Override
    public Object selectByState(short state, String useType) {
        if (useType.equals(TruckType.tankTruck.toString())) {
            return dao.selectByState(state, useType);
        } else {
            List<TruckInfoEntity> truckList = dao.selectByState(state, useType);
            List<Map<String, Object>> resultMap = new ArrayList<>();
            for (TruckInfoEntity entity : truckList) {
                var entityMap = entity.toMap();
                var Overage = Overagedao.findByState(entity.getSn());
                if (Overage.size() > 0) {
                    if (Overage.get(0) != null) {
                        entityMap.put("Overage", Overage.get(0));
                    }
                } else {
                    entityMap.put("Overage", null);
                }
                resultMap.add(entityMap);
            }
            return resultMap;
        }

    }

    @Override
    public Map<String, Object> queryAll(String useType, String cateSN) {
        //获取砂浆调度车辆信息
        if (useType.equals("Mortar")) {
            var car = dao.queryMortarTruck();
            Map<String, Object> result = new HashMap<String, Object>();
            List<Map<String, Object>> result0 = new ArrayList<Map<String, Object>>();
            List<Object> result1 = new ArrayList<Object>();
            List<Object> result2 = new ArrayList<Object>();
            List<Object> result3 = new ArrayList<Object>();
            car.stream().filter(y -> y.getState() == TruckState.LEISURE.code).forEach(t -> {
                var data = t.toMap();
                var Overage = Overagedao.findByState(t.getSn());
                if (Overage.size() > 0) {
                    if (Overage.get(0) != null) {
                        data.put("Overage", Overage.get(0));
                    }
                } else {
                    data.put("Overage", null);
                }
                result0.add(data);
            });

            result.put("idle", result0);
            var lineList = linedao.queryListByProductCate(cateSN);
            lineList.forEach(n -> {
                var line = n.toMap();
                List<TruckInfoEntity> truckList = new ArrayList<>();
                car.stream().filter(y -> y.getState() == TruckState.WAITING.code).forEach(t -> {
                    var taskcar = Taskdao.queryListByTaskCar(t.getTruckCode());
                    line.put("task", null);
                    line.put("productTask", null);
                    if (taskcar.size() > 0) {
                        if (taskcar.get(0) != null) {
                            if (taskcar.get(0).getProductionLineSN().equals(n.getSn())) {
                                truckList.add(t);
                                line.put("task", taskcar.get(0));
                                var productTask = ProductTaskdao.findBySN(taskcar.get(0).getProductionTaskSN());
                                line.put("productTask", productTask);
                            }
                        }
                    }
                });
                line.put("car", truckList);
                result1.add(line);
            });
            result.put("waiting", result1);
            car.stream().filter(y -> y.getState() == TruckState.BUSING.code || y.getState() == TruckState.ARRIVED.code || y.getState() == TruckState.RETURNING.code).forEach(t -> {
                var taskcar = Taskdao.queryListByTaskCar(t.getTruckCode());
                var data = t.toMap();
                var Overage = Overagedao.findByState(t.getSn());
                if (Overage.size() > 0) {
                    if (Overage.get(0) != null) {
                        data.put("Overage", Overage.get(0));
                    }
                } else {
                    data.put("Overage", null);
                }
                var shiporder = shipOrderdao.findListByTruckCode(t.getTruckCode());
                data.put("productorder", shiporder);
                result2.add(data);
            });
            result.put("busy", result2);
            car.stream().filter(y -> y.getState() == TruckState.REPAIR.code).forEach(t -> {
                var data = t.toMap();
                result3.add(data);
            });
            result.put("repair", result3);
            return result;
        } else {
            var car = dao.queryAll(useType);
            Map<String, Object> result = new HashMap<String, Object>();
            List<Object> result0 = new ArrayList<Object>();
            List<Object> result1 = new ArrayList<Object>();
            List<Object> result2 = new ArrayList<Object>();
            List<Object> result3 = new ArrayList<Object>();

            var ovTruckList = car.stream().filter(y -> y.getState() == TruckState.LEISURE.code).toList();
            List<ProductOverageEntity> ovList = new ArrayList<ProductOverageEntity>();
            if (ovTruckList.size() > 0) {
                ovList = Overagedao.queryListByTruckSNList(ovTruckList.stream().map(t -> t.getSn()).toList());
            }
            var zctruck = shipOrderdao.queryByState((short) 0);
            List<ProductOverageEntity> finalOvList = ovList;
            ovTruckList.forEach(t -> {
                var entityss = zctruck.stream().filter(s->s.getTruckSN().equals(t.getSn()));
                if(entityss.isParallel()){
                    t.setTareWeight(Double.valueOf(entityss.findFirst().get().getTareWeight().toString()));
                }
                var data = t.toMap();
                var Overage = finalOvList.stream().filter(o -> o.getTruckSN().equals(t.getSn())).toList();
                if (Overage.size() > 0) {
                    if (Overage.get(0) != null) {
                        data.put("Overage", Overage.get(0));
                    }
                } else {
                    data.put("Overage", null);
                }
                result0.add(data);
            });
            result.put("idle", result0);
            var lineList = linedao.queryListByProductCate(cateSN);
            var waitTruckList = car.stream().filter(y -> y.getState() == TruckState.WAITING.code).toList();
            List<TransTaskEntity> waitTransTaskList = new ArrayList<>();
            var waitTruckSNList = waitTruckList.stream().map(t -> t.getSn()).toList();
            if (waitTruckSNList.size() > 0) {
                waitTransTaskList.addAll(Taskdao.queryListByTruckSNList(waitTruckSNList));
            }
            List<ProductionTaskEntity> taskList = new ArrayList<>();
            if (waitTransTaskList.size() > 0) {
                var taskSNList = waitTransTaskList.stream().map(t -> t.getProductionTaskSN()).distinct().toList();
                if (taskSNList.size() > 0) {
                    taskList.addAll(ProductTaskdao.queryListBySNList(taskSNList));
                }
            }
            lineList.forEach(n -> {
                var line = n.toMap();
                List<Object> truckList = new ArrayList<>();
                line.put("task", null);
                line.put("productTask", null);
                waitTruckList.forEach(t -> {
                    var taskOpt = waitTransTaskList.stream().filter(p -> p.getTruckSN().equals(t.getSn()) && p.getProductionLineSN().equals(n.getSn())).findFirst();
                    if (taskOpt.isPresent()) {
                        var task = taskOpt.get();
                        var carEntity = t.toMap();
                        carEntity.put("task", task);
                        var ptOpt = taskList.stream().filter(p -> p.getSn().equals(task.getProductionTaskSN())).findFirst();
                        carEntity.put("productTask", ptOpt.isPresent() ? ptOpt.get() : new ProductionTaskEntity());
                        truckList.add(carEntity);
                    }
                });
                line.put("car", truckList);
                result1.add(line);
            });
            result.put("waiting", result1);
            var runningTruckList = car.stream().filter(y -> y.getState() == TruckState.BUSING.code || y.getState() == TruckState.ARRIVED.code || y.getState() == TruckState.RETURNING.code).toList();
            var runTruckSNList = runningTruckList.stream().map(t -> t.getSn()).toList();
            List<ProductOverageEntity> runTruckOvList = new ArrayList<>();
            List<ProductShipOrderEntity> runTruckLastOrderList = new ArrayList<>();
            if (runTruckSNList.size() > 0) {
                runTruckOvList.addAll(Overagedao.queryListByTruckSNList(runTruckSNList));
                runTruckLastOrderList.addAll(shipOrderdao.queryLastOrderListByTruckSNList(runTruckSNList));
            }

            runningTruckList.forEach(t -> {

                var data = t.toMap();
                var ovOpt = runTruckOvList.stream().filter(p -> p.getTruckSN().equals(t.getSn())).findFirst();
                if (ovOpt.isPresent()) {
                    data.put("Overage", ovOpt.get());
                } else {
                    data.put("Overage", null);
                }
                var orderOpt = runTruckLastOrderList.stream().filter(o -> o.getTruckSN().equals(t.getSn())).findFirst();
                data.put("productorder", orderOpt.isPresent() ? orderOpt.get() : new ProductShipOrderEntity());
                if (orderOpt.isPresent()) {
                    var ship = orderOpt.get();
                    var ss = ProductTaskdao.findBySN(ship.getTaskSN());
                    if (ss!=null) {
                        var dd = ss.getTimeoutDuration();
                        if (dd != null && dd.compareTo(BigDecimal.valueOf(0)) != 0) {
                            if ((System.currentTimeMillis() - ship.getOutTime().getTime()) / ((1000 * 60 * 60) * 1.000F) > Float.valueOf(String.valueOf(dd))) {
                                data.put("timeout", true);
                            } else {
                                data.put("timeout", false);
                            }
                        } else {
                            var out = HsApp.getSystemSet("timeout") == null ? "2" : HsApp.getSystemSet("timeout");
                            if (ship.getOutTime() != null) {
                                if ((System.currentTimeMillis() - ship.getOutTime().getTime()) / ((1000 * 60 * 60) * 1.000F) > Float.valueOf(out)) {
                                    data.put("timeout", true);
                                } else {
                                    data.put("timeout", false);
                                }
                            }
                        }
                    } else {
                        var out = HsApp.getSystemSet("timeout") == null ? "2" : HsApp.getSystemSet("timeout");
                        if (ship.getOutTime() != null) {
                            if ((System.currentTimeMillis() - ship.getOutTime().getTime()) / ((1000 * 60 * 60) * 1.000F) > Float.valueOf(out)) {
                                data.put("timeout", true);
                            } else {
                                data.put("timeout", false);
                            }
                        }
                    }
                }
                result2.add(data);
            });
            result.put("busy", result2);
            car.stream().filter(y -> y.getState() == TruckState.REPAIR.code).forEach(t -> {
                var data = t.toMap();
                result3.add(data);
            });
            result.put("repair", result3);
            return result;
        }

    }

    @Override
    public TruckInfoEntity queryByTruckCode(String truckCode) {
        return dao.queryByTruckCode(truckCode);
    }

    @Override
    public Long findMaxSortCode(String useType) {
        return dao.findMaxSortCode(useType);
    }

    @Override
    public TruckInfoEntity findByCardSn(String cardSNO) {
        return dao.findByCardSn(cardSNO);
    }

    @Override
    public TruckInfoEntity findByTruck(String truck) {
        return dao.findByTruck(truck);
    }

    @Override
    public List<TruckInfoEntity> findAll() {
        return dao.findAll();
    }

    @Override
    public Map<String, Object> findStateAll() {
        List<TruckInfoEntity> all = dao.findStateAll();
        var inTransit = all.stream().filter(t -> t.getState() == 30).toList().size();
        var waiting = all.stream().filter(t -> t.getState() == 20).toList().size();
        var maintenance = all.stream().filter(t -> t.getState() == 90).toList().size();
        var inProduction = all.stream().filter(t -> t.getState() == 40).toList().size();
        var productShipOrderEntity = shipOrderdao.selectProduct();
        var departCount = productShipOrderEntity.getId();
        var shippingWeight = productShipOrderEntity.getNetWeight();
        Map<String, Object> map = new HashMap<>();

        var productShipOrderEntitiesYear = shipOrderdao.selectProductNetWeight(1);
        //车牌号与对应的运输年总重量
        map.put("year", productShipOrderEntitiesYear);
        var productShipOrderEntitiesMonth = shipOrderdao.selectProductNetWeight(2);
        //车牌号与对应的月运输总重量
        map.put("month", productShipOrderEntitiesMonth);
        var productShipOrderEntitiesDay = shipOrderdao.selectProductNetWeight(3);
        //车牌号与对应的日运输总重量
        map.put("day", productShipOrderEntitiesDay);


        //平均单车运输量
        map.put("shippingWeight", shippingWeight);
        //发车总数量
        map.put("departCount", departCount);
        //运输中
        map.put("inTransit", inTransit);
        //等待中
        map.put("waiting", waiting);
        //维修中
        map.put("maintenance", maintenance);
        //生产中
        map.put("inProduction", inProduction);
        return map;
    }

    @Override
    public TruckInfoEntity queryBydriverSN(String driverSN) {
        return dao.queryBydriverSN(driverSN);
    }

    @Override
    public boolean truckBack(TruckInfoEntity truck) {
        if (truck != null) {
            if (Tl.timeToMinute((new Date()).getTime() - truck.getBackTime().getTime()) > Tl.getInteger(HsApp.getSystemSet(CK.Truck_Back_Interval), 0)) {
                if (truck.getState() == 20 || truck.getState() == 30 || truck.getState() == 50 || truck.getState() == 60 || truck.getState() == 90) {
                    truck.setState((short) 10);
                    truck.setBackTime(new Date());
                    truck.setSortCode(dao.findMaxSortCode(truck.getUseType()) + 1);
                    return dao.update(truck) > 0;
                }
            }
        }
        return false;
    }

    @Override
    public TruckInfoEntity findByOpenid(String openid) {
        var wxuser = dao.findByOpenid(openid);
        if (wxuser != null) {
            return wxuser;
        }
        var result = dao.findByWxOpenid(openid);
        return result;
    }


}